package cn.com.generaldata.os.service.impl;

import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.dom4j.DocumentException;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.impl.sql.SqlTemplate;
import org.nutz.json.Json;
import org.nutz.lang.Mirror;
import org.nutz.lang.random.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import cn.com.generaldata.jsme_indicator_system.entity.AreaPerformNz;
import cn.com.generaldata.jsme_indicator_system.entity.Indicator;
import cn.com.generaldata.jsme_indicator_system.entity.ReportDetailNz;
import cn.com.generaldata.jsme_indicator_system.entity.ReportNz;
import cn.com.generaldata.jsme_indicator_system.entity.ReportTypeNz;
import cn.com.generaldata.jsme_indicator_system.entity.UnitNz;
import cn.com.generaldata.jsme_indicator_system.util.Constants;
import cn.com.generaldata.jsme_indicator_system.util.Constants.INDICATORTYPE;
import cn.com.generaldata.os.service.impl.HibernateInterceptor.InterceptorEvent;
import cn.com.generaldata.os.util.DefaultPasswordEncoder;
import cn.com.generaldata.os.util.RSAUtil;
import cn.com.generaldata.os.util.SecurityUtil;
import cn.com.generaldata.os.vo.webservice.ExcuteXMLVO;
import cn.com.generaldata.os.vo.webservice.IdentityVO;
import cn.com.generaldata.os.vo.webservice.IndicatorVO;
import cn.com.generaldata.os.vo.webservice.ReportVO;
import cn.com.generaldata.os.vo.webservice.ReturnStateVO;
import cn.com.generaldata.os.vo.webservice.RowVO;
import cn.com.generaldata.os.vo.webservice.TypeVO;

import com.IndicatorGisWSInterface;
import com.IndicatorGisWSService;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;

@Service
public class CommonJsonReport {

	@Value("${gjme.serviceId}")
	private String serviceId;
	@Value("${gjme.username}")
	private String username;
	@Value("${gjme.password}")
	private String password;
	@Value("${gjme.projectUrl}")
	private String serviceUrl;
	@Autowired
	private Dao dao;

	@Autowired
	private SqlTemplate sqlTemplate;

	private final Mirror<ReportDetailNz> mirrorReportDetail = Mirror.me(ReportDetailNz.class);

	/**
	 * 生成加密密码
	 * @param username
	 * @param datetime
	 * @param password
	 * @return
	 */
	private String generalMD5PW(String username, String datetime, String password) {
		//先将密码md5散列化
		String encodePW = new DefaultPasswordEncoder("MD5").encode(password);
		//生成组合密码
		String encode = new DefaultPasswordEncoder("MD5").encode(serviceId + username + datetime + encodePW);
		return encode;
	}


	/**
	 * 自动生成报文调用接口
	 * @param report
	 * @param event
	 */
	public void createJsonReport(ReportNz report, InterceptorEvent event) {
		String json = fillJson(report, event);
		String error = "";
		String[] codeMsg = new String[2];
		//回执内容
		try {
			String response = excuteJsonSecurity(json);
			System.out.println(response);
			codeMsg = getResponse(response);
		} catch (Exception e) {
			error = e.getMessage();
			// TODO Auto-generated catch block
			codeMsg[0] = "001";
			codeMsg[1] = "接口不通";
		}
		saveLog(report, codeMsg, error);

	}


	private String fillJson(ReportNz report, InterceptorEvent event) {
		//生成当前时间戳
		String datetime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH-mm-ss");
		ExcuteXMLVO excute=new ExcuteXMLVO();
		IdentityVO identity=new IdentityVO();
		identity.setServiceId(serviceId);
		identity.setUsername(username);
		identity.setTime(datetime);
		if (event == InterceptorEvent.DELETE) {
			identity.setOperateType("0");
		} else {
			identity.setOperateType("1");
		}
		String md5pw = generalMD5PW(username, datetime, password);
		identity.setPassword(md5pw);
		excute.setIdentity(identity);
		ReportVO reportVO = fillElement(report, event);
		excute.setReport(reportVO);
		return  Json.toJson(excute);
	}

	private void saveLog(ReportNz report, String[] codeMsg, String error) {
		//频度reportTypeNz.getTypeTime()
		String typeTime = report.getReportTimetype();
		String typeYearTime = report.getReportYearTime();
		//半年报seqYear
		if (Constants.INDICATOR_FULL_YEAR.equals(typeTime) && StringUtils.isNotBlank(typeYearTime)
				&& Constants.REPORT_HALF_YEAR.equals(Integer.valueOf(typeYearTime)))
			typeTime = Constants.HALF_YEAR + "";
		int seqYear = 1;
		String reportName = "";
		switch (Integer.valueOf(typeTime).intValue()) {
		case Constants.FULL_YEAR:
			seqYear = Constants.FULL_YEAR;
			reportName = report.getReportYear() + "年报";
			break;
		case Constants.HALF_YEAR:
			if ((Constants.REPORT_TIME_HALF_YEAR + "").equals(report.getReportYearTime()))
				reportName = report.getReportYear() + "下半年报";
			//上半年报
			else if ((Constants.REPORT_HALF_YEAR + "").equals(report.getReportYearTime()))
				reportName = report.getReportYear() + "上半年报";
			break;
		case Constants.MONTH_REPORT:
			seqYear = report.getMonth();
			reportName = report.getReportYear() + "年" + seqYear + "月";
			break;
		case Constants.QUARTER_REPORT:
			seqYear = report.getQuarter();
			reportName = report.getReportYear() + "年" + seqYear + "季";
			break;
		}
//		TransLogNz log = new TransLogNz();
//		log.setId(R.UU16());
//		log.setReportYear(report.getReportYear());
//		log.setReportId(report.getId());
//		log.setReportName(reportName + report.getReportType());
//		log.setUnitName(report.getReportUnit());
//		log.setCreateDate(new Date());
//		log.setCode(codeMsg[0]);
//		log.setContent(codeMsg[1]);
//		log.setErrorMsg(error);
//		dao.insert(log);
	}

	private String[] getResponse(String response) throws DocumentException {
		ExcuteXMLVO excuteXMLReturn = Json.fromJson(ExcuteXMLVO.class, response);
		//根节点
		ReturnStateVO returnState = excuteXMLReturn.getReturnState();
		String returnCode = returnState.getReturnCode();
		String returnMessage = returnState.getReturnMessage();
		String[] codeMsg = new String[2];
		codeMsg[0] = returnCode;
		codeMsg[1] = returnMessage;
		return codeMsg;
	}

	/**
	 * 拼接Document
	 * @param rowsList
	 * @param numDigits
	 * @param areaMap
	 */
	private ReportVO fillElement(ReportNz report, InterceptorEvent event) {
		ReportVO reportElement =new ReportVO();
		ReportTypeNz reportTypeNz = dao.fetch(ReportTypeNz.class, report.getReportTypeId());
		AreaPerformNz areaPerformNz = dao.fetch(AreaPerformNz.class, report.getReportAreaId());
		UnitNz unitNz = dao.fetch(UnitNz.class, report.getUnitId());
		//表号
		reportElement.setReportNo(reportTypeNz.getTypeNo());
		//单位的区划代码
		reportElement.setRegionCode(areaPerformNz.getAreaCode());
		//组织机构代码
		reportElement.setUnitCode(StringUtils.isBlank(unitNz.getUnitInstitutionCode())?unitNz.getDl():unitNz.getUnitInstitutionCode());
		//报表年份
		reportElement.setReportYear(report.getReportYear());
		reportElement.setContactPerson(report.getReportUnitAdmin());
		reportElement.setUserStatAdmin(report.getReportStatAdmin());
		reportElement.setUserStat(report.getReportFillAdmin());
		//频度
		String typeTime = reportTypeNz.getTypeTime();
		String typeYearTime = reportTypeNz.getTypeYearTime();
		//半年报seqYear
		if (Constants.INDICATOR_FULL_YEAR.equals(typeTime) && StringUtils.isNotBlank(typeYearTime)
				&& Constants.REPORT_HALF_YEAR.equals(Integer.valueOf(typeYearTime))){
			typeTime = Constants.REPORT_TIME_HALF_YEAR + "";
		}
		reportElement.setFrequency(typeTime);
		int seqYear = 1;
		switch (Integer.valueOf(typeTime).intValue()) {
		case Constants.FULL_YEAR:
			seqYear = Constants.FULL_YEAR;
			break;
		case Constants.HALF_YEAR:
			//下半年报
			if ((Constants.REPORT_TIME_HALF_YEAR + "").equals(report.getReportYearTime()))
				seqYear = Constants.REPORT_TIME_HALF_YEAR;
			//上半年报
			else if ((Constants.REPORT_HALF_YEAR + "").equals(report.getReportYearTime()))
				seqYear = Constants.REPORT_HALF_YEAR;
			break;
		case Constants.MONTH_REPORT:
			seqYear = report.getMonth();
			break;
		case Constants.QUARTER_REPORT:
			seqYear = report.getQuarter();
			break;
		}
		reportElement.setSeqYear(seqYear + "");
		reportElement.setReportStatus(report.getReportCheckStatus()+"");
		List<RowVO> rowList =Lists.newArrayList();
		//删除操作没必要取内容
		if (event != InterceptorEvent.DELETE){
			rowList=fillBodyElement(report);
		}
		reportElement.setRows(rowList);
		return reportElement;
	}

	/**
	 * 报文体
	 * @param rowsElement
	 * @param report
	 */
	private List<RowVO> fillBodyElement(ReportNz report) {
		List<RowVO> rows=Lists.newArrayList();
		List<Indicator> indicatorList = queryReportTypeListIndicator(report.getReportTypeId());
		List<ReportDetailNz> detailList = dao.query(ReportDetailNz.class, Cnd.where("reportId", "=", report.getId()));
		Table<Integer, String, List<Indicator>> indicatorRowList = HashBasedTable.create();
		List<Indicator> list = Lists.newArrayList();
		//将同代码的指标放到一起（区分不同的属性）
		for (Indicator indicator : indicatorList) {
			if (indicatorRowList.get(indicator.getRow(), indicator.getCode()) == null) {
				list = Lists.newArrayList();
			} else {
				list = indicatorRowList.get(indicator.getRow(), indicator.getCode());
			}
			list.add(indicator);
			indicatorRowList.put(indicator.getRow(), indicator.getCode(), list);
		}
		for (ReportDetailNz detail : detailList) {
			RowVO rowElement=new RowVO();
			int rowIndex = detail.getRowIndex();
			//行号
			rowElement.setRowIndex(rowIndex + "");
			Map<String, List<Indicator>> row = indicatorRowList.row(rowIndex);
			Set<String> keySet = row.keySet();
			List<IndicatorVO> indicatorVOList=Lists.newArrayList();
			rowElement.setIndicator(indicatorVOList);
			for (String code : keySet) {
				IndicatorVO indicatorElement=new IndicatorVO();
				fillIndicator(detail, indicatorElement, row, code);
				indicatorVOList.add(indicatorElement);
			}
			rows.add(rowElement);
		}
		return rows;
	}

	/**
	 * 拼接指标信息
	 * @param detail
	 * @param rowElement
	 * @param row
	 * @param code
	 */
	private void fillIndicator(ReportDetailNz detail, IndicatorVO indicatorElement, Map<String, List<Indicator>> row, String code) {
		List<Indicator> codeList = row.get(code);
		indicatorElement.setIndicatorNo(code);
		int i = 0;
		for (Indicator indicator : codeList) {
			Integer column = indicator.getTheColumn();
			if (i == 0){
				indicatorElement.setIndicatorMeaSure(indicator.getMeasureCode());
			}
			String value = mirrorReportDetail.getValue(detail, "f" + column).toString();
			List<TypeVO> typeList=Lists.newArrayList();
			indicatorElement.setType(typeList);
			if (indicator.getName().endsWith("-累计")){
				TypeVO typeElement = new TypeVO();
				typeElement.setIndicatorType(INDICATORTYPE.CURRENTTOTAL.getCode());
				typeElement.setIndicatorValue(value);
				typeList.add(typeElement);
			}
			else if (indicator.getName().endsWith("-上年同期")){
				TypeVO typeElement = new TypeVO();
				typeElement.setIndicatorType(INDICATORTYPE.LASTCURRENT.getCode());
				typeElement.setIndicatorValue(value);
				typeList.add(typeElement);
			}
			else if (indicator.getName().endsWith("-上期")){
				TypeVO typeElement = new TypeVO();
				typeElement.setIndicatorType(INDICATORTYPE.PRIOR.getCode());
				typeElement.setIndicatorValue(value);
				typeList.add(typeElement);
			}
			else if (indicator.getName().endsWith("-上期累计")){
				TypeVO typeElement = new TypeVO();
				typeElement.setIndicatorType(INDICATORTYPE.PRIORTOTAL.getCode());
				typeElement.setIndicatorValue(value);
				typeList.add(typeElement);
			}
			else if (indicator.getName().endsWith("-上年累计")){
				TypeVO typeElement = new TypeVO();
				typeElement.setIndicatorType(INDICATORTYPE.LASTTOTAL.getCode());
				typeElement.setIndicatorValue(value);
				typeList.add(typeElement);
			}
			else{
				TypeVO typeElement = new TypeVO();
				typeElement.setIndicatorType(INDICATORTYPE.CURRENT.getCode());
				typeElement.setIndicatorValue(value);
				typeList.add(typeElement);
			}
			i++;
		}
	}

	/**
	 * 报表指标
	 * @param typeId
	 * @return
	 */
	private List<Indicator> queryReportTypeListIndicator(String typeId) {
		String sql = "select idi.*,rti.row_index,rti.the_column,tm.code as measure_code from t_indicator idi left join t_measure tm on idi.measure_id=tm.id inner join t_report_type_indicator rti on idi.id=rti.indicator_id where rti.report_type_id=@typeId order by rti.row_index,the_column";
		Map params = Maps.newHashMap();
		params.put("typeId", typeId);
		List<Indicator> list = sqlTemplate.query(sql, params, Indicator.class);
		return list;
	}
	
	//执行json加密传输
		public String excuteJsonSecurity(String asJson){
//			String asJson="";
//			try {
//				asJson = FileUtils.readFileToString(new File(filePath), "UTF-8");
//			} catch (IOException e) {
//				e.printStackTrace();
//			}
			// 使用服务器端的公钥对要传出去的数据进行加密
			try {
				RSAUtil rsaUtil=SecurityUtil.getCoder();
				String serverPublicKey = getPublicKey(serviceUrl);
				RSAPublicKey serverKey = rsaUtil.getPublicKey(rsaUtil.decodeBase64(serverPublicKey));
				byte[] encryptData = rsaUtil.encrypt(serverKey, asJson.getBytes(Charset.forName("utf-8")));
				//加密后的数据
				String params = rsaUtil.encodeBase64(encryptData);
				IndicatorGisWSInterface transferWSPort = genWebService(serviceUrl);

				//调用接口服务(测试方法)，传入数据文件字符串，客户端公钥，返回回执字符串信息
				String responseArray = transferWSPort.transferDataSecurityForJson(params,rsaUtil.getPublicCSharp());

				//回执信息，回执信息也可按dome结构解析
				// 使用自己的私钥进行解密
				String privateCSharp = rsaUtil.getPrivateCSharp();
				RSAPrivateKey privateKey = rsaUtil.getPrivateKey(rsaUtil.decodeBase64(privateCSharp));
				String result=new String(rsaUtil.decrypt(privateKey, rsaUtil.decodeBase64(responseArray)),"utf-8");
				System.out.println("从服务器端返回的字符串结果是:"+result);
				return result;
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return null;
		}
		
		private IndicatorGisWSInterface genWebService(String serviceUrl) {
			//调用接口WebService地址
			URL url = null;
			try {
				url = new URL(serviceUrl);
			} catch (MalformedURLException e1) {
				e1.printStackTrace();
			}
			//用wsdl2java将接口WebService生成客户端调用的程序
			IndicatorGisWSService transferService = new IndicatorGisWSService(url);
			IndicatorGisWSInterface transferWSPort = transferService.getIndicatorGisWSPort();
			return transferWSPort;
		}
		
		public String getPublicKey(String serviceUrl) {
			//省级接口url
			IndicatorGisWSInterface transferWSPort = genWebService(serviceUrl);
			String serverPublicKey = transferWSPort.getServerPublicKey();
			System.out.print("从服务器端得到的公钥为:");
			return serverPublicKey;
		}
}
